(defn qpop (filo)
 "Helper function that acts as a queue pop. Removes first element in array and returns it."
 (def- s (get filo 0))
 (array/remove filo 0)
 s)

(def eval-f-parse (partial string/split " "))


(def [gfvenv gfmenv] 
     [#@{"+" + "-" - "*" * ""} 
       (zipcoll (map string (all-bindings)) (map eval (all-bindings)))
       #This may be unwished for as it grabs the whole environment and shoves it in. Consider a custom restricted environment (as commented out above, for instance) instead.
      @{
        "!" (fn ! (e-i) 
             (let 
              (rear (e-i :rear)
               front (e-i :front)
               Z (- (inc (array/pop rear)))
               F (array/pop rear)
               S (array/slice rear Z))
                  (set (e-i :rear) (array/slice rear 0 Z)) #Remove S from rear.
                  (array/push (e-i :rear) (apply F S)))) }])

(defn eval-f-token (eval-interface)
 "Eval a single token (string) out of an eval-interface. Expects (eval-interface :front) not empty."
   (var- tkn (qpop (eval-interface :front))) # Pop queue.
   (var- mac (get (eval-interface :macro-env) tkn))
   (var- rear (eval-interface :rear))
   (cond mac (mac eval-interface)
        (scan-number tkn ) (array/push rear (scan-number tkn))
        (not= tkn "") (array/push rear
        ((match (string/bytes tkn)
         @[58] keyword
         @[39]   symbol
         '(35 116) (fn (_) true) #"#t"
         '(35 102) (fn (_) false)#"#f"
         #@[34]   string #Not really, because spaces.
	 _ (fn (_) ((eval-interface :value-env) tkn))) 
         (string/slice tkn 1)))))

(def eval-interface-proto 
 "The interface prototype Felth-janet uses for evaling."
 @{:rear @[] :front @[] #:token nil
   :value-env gfvenv :macro-env gfmenv} )

(defn eval-f-eval (eval-interface)
 "Raw Felth eval function. Takes an eval-interface."
 (if (not (getproto eval-interface)) (table/setproto eval-interface eval-interface-proto))
 (eval-f-token eval-interface)
 (if (empty? (eval-interface :front)) eval-interface (eval-f-eval eval-interface)))

(defn eval-f (str &opt fmenv fvenv stk)
 "Felth's loadstring or evalstring."
  (default fmenv gfmenv) (default fvenv gfvenv)
  (eval-f-eval @{:rear @[] :front (eval-f-parse str) :macro-env fmenv :value-env fvenv}))

(defn eval-f-repl ()
 "Run a simple REPL for Felth-janet."
 (while true
  (prin "=>")
  (let ([s rv] (protect (eval-f (string/trim (file/read stdin :line)) ))) (prin (if s "=< " "!< ")) (pp (if s (rv :rear) rv)))))
  #(let([s rv] (protect (eval-f  (file/read stdin :line))))
(eval-f-repl)

